/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ext_dev.h"
#include "gpio_if.h"

#define KEY_NUM 2
#define KEY0_GPIO 7
#define KEY1_GPIO 8

typedef struct {
    ExtDevKeyIdDef id;
    uint16_t gpioMap;
    ExtDevKeyStsNoticeCbDef StsNoticeCb;
} ExtDevKeyManageDef;

static ExtDevKeyManageDef g_extDevKeyManage[KEY_NUM] = {
    {
        .id = EXT_DEV_KEY_0,
        .gpioMap = KEY0_GPIO,
        .StsNoticeCb = NULL,
    },
    {
        .id = EXT_DEV_KEY_1,
        .gpioMap = KEY1_GPIO,
        .StsNoticeCb = NULL,
    },
};

static int32_t ExtDevInterKeyRisingIrqHandler(uint16_t gpio, void *data);

static int32_t ExtDevInterKeyFallingIrqHandler(uint16_t gpio, void *data)
{
    ExtDevKeyIdDef extDevKeyId = *(ExtDevKeyIdDef *)data;
    if ((gpio != g_extDevKeyManage[extDevKeyId].gpioMap) || (NULL == g_extDevKeyManage[extDevKeyId].StsNoticeCb)) {
        LOG_E("unexpected irq from gpio %d or extDevKeyStsNoticeCb is NULL.", gpio);
        return HDF_FAILURE;
    }
    if (HDF_SUCCESS != GpioUnsetIrq(gpio, NULL)) {
        LOG_E("Unset Key%d gpio%d irq failed!", extDevKeyId, gpio);
        return EXT_DEV_ERROR;
    }
    if (HDF_SUCCESS != GpioSetIrq(gpio, OSAL_IRQF_TRIGGER_RISING, ExtDevInterKeyRisingIrqHandler,
                                  &(g_extDevKeyManage[extDevKeyId].id))) {
        LOG_E("Set Key%d gpio%d irq failed!", extDevKeyId, gpio);
        return EXT_DEV_ERROR;
    }
    if (HDF_SUCCESS != GpioEnableIrq(gpio)) {
        LOG_E("enable Key%d gpio%d irq failed!", extDevKeyId, gpio);
        GpioUnsetIrq(gpio, NULL);
        return EXT_DEV_ERROR;
    }
    g_extDevKeyManage[extDevKeyId].StsNoticeCb(EXT_DEV_IR_NO_MAN);
    return HDF_SUCCESS;
}

static int32_t ExtDevInterKeyRisingIrqHandler(uint16_t gpio, void *data)
{
    ExtDevKeyIdDef extDevKeyId = *(ExtDevKeyIdDef *)data;
    if ((gpio != g_extDevKeyManage[extDevKeyId].gpioMap) || (NULL == g_extDevKeyManage[extDevKeyId].StsNoticeCb)) {
        LOG_E("unexpected irq from gpio %d or extDevKeyStsNoticeCb is NULL.", gpio);
        return HDF_FAILURE;
    }
    if (HDF_SUCCESS != GpioUnsetIrq(gpio, NULL)) {
        LOG_E("Unset Key%d gpio%d irq failed!", extDevKeyId, gpio);
        return EXT_DEV_ERROR;
    }
    if (HDF_SUCCESS != GpioSetIrq(gpio, OSAL_IRQF_TRIGGER_FALLING, ExtDevInterKeyFallingIrqHandler,
                                  &(g_extDevKeyManage[extDevKeyId].id))) {
        LOG_E("Set Key%d gpio%d irq failed!", extDevKeyId, gpio);
        return EXT_DEV_ERROR;
    }
    if (HDF_SUCCESS != GpioEnableIrq(gpio)) {
        LOG_E("enable Key%d gpio%d irq failed!", extDevKeyId, gpio);
        GpioUnsetIrq(gpio, NULL);
        return EXT_DEV_ERROR;
    }
    g_extDevKeyManage[extDevKeyId].StsNoticeCb(EXT_DEV_IR_HAVE_MAN);
    return HDF_SUCCESS;
}

static ExtDevCtlRst ExtDevInterKeyUnInitNotice(ExtDevKeyIdDef extDevKeyId)
{
    GpioUnsetIrq(g_extDevKeyManage[extDevKeyId].gpioMap, NULL);
    g_extDevKeyManage[extDevKeyId].StsNoticeCb = NULL;

    return EXT_DEV_SUCCESS;
}

static ExtDevCtlRst ExtDevInterKeyInitNotice(ExtDevKeyIdDef extDevKeyId, ExtDevKeyStsNoticeCbDef extDevKeyStsNoticeCb)
{
    if (NULL == extDevKeyStsNoticeCb) {
        LOG_E("Key%d notice callback function is NULL!", extDevKeyId);
        return EXT_DEV_ERROR;
    }
    if (HDF_SUCCESS != GpioSetIrq(g_extDevKeyManage[extDevKeyId].gpioMap, OSAL_IRQF_TRIGGER_RISING,
                                  ExtDevInterKeyRisingIrqHandler, &(g_extDevKeyManage[extDevKeyId].id))) {
        LOG_E("Set key%d gpio%d irq failed!", extDevKeyId, g_extDevKeyManage[extDevKeyId].gpioMap);
        return EXT_DEV_ERROR;
    }
    if (HDF_SUCCESS != GpioEnableIrq(g_extDevKeyManage[extDevKeyId].gpioMap)) {
        LOG_E("enable key%d gpio%d irq failed!", extDevKeyId, g_extDevKeyManage[extDevKeyId].gpioMap);
        GpioUnsetIrq(g_extDevKeyManage[extDevKeyId].gpioMap, NULL);
        return EXT_DEV_ERROR;
    }
    g_extDevKeyManage[extDevKeyId].StsNoticeCb = extDevKeyStsNoticeCb;
    return EXT_DEV_SUCCESS;
}
ExtDevCtlRst ExtDevKeyInit(ExtDevKeyCfgDef *extDevKeyCfg, int keyNum)
{
    if (extDevKeyCfg == NULL || keyNum > KEY_NUM || keyNum <= 0) {
        LOG_E("invalid params! \n");
        return EXT_DEV_ERROR;
    }

    for (int i = 0; i < keyNum; i++) {
        if (HDF_SUCCESS != GpioSetDir(g_extDevKeyManage[i].gpioMap, GPIO_DIR_IN)) {
            LOG_E("Set Key%d gpio%d dir in failed!", extDevKeyCfg[i].extDevKeyId, g_extDevKeyManage[i].gpioMap);
            return EXT_DEV_ERROR;
        }

        if (EXT_DEV_KEY_OBTAIN == extDevKeyCfg[i].extDevKeyWorkType) {
            if (EXT_DEV_SUCCESS != ExtDevInterKeyUnInitNotice(extDevKeyCfg[i].extDevKeyId)) {
                LOG_E("Key obtain work type init failed.");
                return EXT_DEV_ERROR;
            }
        } else if (EXT_DEV_KEY_NOTICE == extDevKeyCfg[i].extDevKeyWorkType) {
            if (EXT_DEV_SUCCESS !=
                ExtDevInterKeyInitNotice(extDevKeyCfg[i].extDevKeyId, extDevKeyCfg[i].extDevKeyStsNoticeCb)) {
                LOG_E("Key notice work type init failed.");
                return EXT_DEV_ERROR;
            }
        } else {
            LOG_E("Unexpected extDevKeyWorkType %d!", extDevKeyCfg[i].extDevKeyWorkType);
            return EXT_DEV_ERROR;
        }
    }

    return EXT_DEV_SUCCESS;
}

/// 按键状态获取
ExtDevKeyMontStsDef ExtDevGetKeySts(ExtDevKeyIdDef extDevKeyId)
{
    uint16_t val = 0;
    ExtDevKeyMontStsDef extDevKeyMontSts = EXT_DEV_KEY_UNPRESS;
    if (HDF_SUCCESS != GpioRead(g_extDevKeyManage[extDevKeyId].gpioMap, &val)) {
        LOG_E("Set ir dir in failed!");
        return HDF_FAILURE;
    }
#ifdef LOW_PRESSED
    extDevKeyMontSts = (val == GPIO_VAL_LOW) ? EXT_DEV_KEY_PRESSED : EXT_DEV_KEY_UNPRESS;
#else
    extDevKeyMontSts = (val == GPIO_VAL_HIGH) ? EXT_DEV_KEY_PRESSED : EXT_DEV_KEY_UNPRESS;
#endif
    return extDevKeyMontSts;
}

int ExtDevKeyIsPress(ExtDevKeyIdDef keyId)
{
    int val = 1;
    int timecnt = 20;
    while (timecnt-- >= 0) {
        osDelay(10);
        if (ExtDevGetKeySts(keyId) == EXT_DEV_KEY_UNPRESS) {
            val = 0;
            break;
        }
    }

    return val;
}
